package e

import (
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/Lofanmi/pinyin-golang/pinyin"
	"github.com/gin-gonic/gin"
	"github.com/goinggo/mapstructure"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	yp "github.com/yunpian/yunpian-go-sdk/sdk"
	"golang.org/x/text/language"
	"golang.org/x/text/message"
	"gopkg.in/gomail.v2"
	"io"
	"io/ioutil"
	"math"
	"math/big"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/pkg/errno"
)

// 封装日志调用
func Log(logType string, args ...interface{}) {

	// 如果正式上线之后，系统会将日志以每天分一个文件存在根目录下面的文件 eg：log/error/20190114.log
	// 创建日志目录
	if config.C.RunMode == "release" {
		logPath := "log/"
		if logType == "err" || logType == "error" || logType == "Err" {
			logPath += "error/"
		} else if logType == "debug" {
			logPath += "debug/"
		} else {
			logPath += "info/"
		}
		res, err := MakeDir(logPath)
		if err != nil || !res {
			log.Error("创建日志目录 [log/] 失败")
		}
		dateStr := time.Now().Format("20060102")
		filePtah := logPath + dateStr + ".log"
		file, err := os.OpenFile(filePtah, os.O_CREATE|os.O_APPEND|os.O_RDWR|os.O_SYNC, 0666)
		if err == nil {
			DelLogPath()
			log.SetOutput(file)
		}
	}

	switch logType {
	case "info", "Info":
		log.Info(args...)
	case "err", "error", "Err":
		log.Error(args...)
	case "bug", "debug":
		log.Debug(args...)
	case "params", "param":
		params, _ := json.Marshal(args)
		log.Info("参数为：", string(params))
	default:
		log.Warn(args...)
	}
}

func LogParams(logType string, Fields interface{}, args ...interface{}) {

	// 转日志输出
	j, _ := json.Marshal(Fields)
	logParams := make(map[string]interface{})
	json.Unmarshal(j, &logParams)

	// 由于Unmarshal int类型会丢失精度转换为float64
	for i, v := range logParams {
		switch v.(type) {
		case float64:
			logParams[i] = int(v.(float64))
		default:
		}
	}

	switch logType {
	case "info", "Info":
		log.WithFields(logParams).Info(args)
	case "err", "error", "Err":
		log.WithFields(logParams).Error(args)
	case "bug", "debug":
		log.WithFields(logParams).Debug(args)
	default:
		log.WithFields(logParams).Warn(args)
	}
}

// 删除7天之前的日志
func DelLogPath() {
	logPath := "log/"
	dataStr := time.Now().AddDate(0, 0, -7).Format("20060102")
	delErrPath := logPath + "error/" + dataStr + ".log"
	delInfoPath := logPath + "info/" + dataStr + ".log"
	os.RemoveAll(delErrPath)
	os.RemoveAll(delInfoPath)
}

// 删除7天之前的下载日志
func DelLogDataPath(logDataPath string) {
	//logDataPath := "log/data/"
	dateStr := time.Now().AddDate(0, 0, -7).Format(TimeFormatD)
	delLogDataPath := logDataPath + dateStr
	Log("err", "准备删除日志目录=", delLogDataPath)
	_, err := os.Stat(delLogDataPath)
	if err == nil {
		Log("err", "日志目录存在", delLogDataPath)
		os.RemoveAll(delLogDataPath)
	}
}

// 创建目录
func MakeDir(dir string) (bool, error) {
	_, err := os.Stat(dir)
	if err == nil {
		return true, nil
	}
	// 不存在目录就创建目录
	err = os.MkdirAll(dir, 0755)
	if err != nil {
		return false, err
	}
	return true, nil
}

func GetUrlName(url string) (name, ext string) {
	filenameWithSuffix := path.Base(url)
	fileSuffix := path.Ext(filenameWithSuffix)
	filename := strings.TrimSuffix(filenameWithSuffix, fileSuffix)
	lowerSuffix := strings.ToLower(fileSuffix)
	return filename, lowerSuffix
}

// 校验APP版本号
func CheckVersion(currentSver string) error {
	//
	//if config.C.RunMode == "debug" {
	//	return nil
	//}
	//if currentSver == "" {
	//	return errno.SverOld
	//}
	//sVer, _ := strconv.Atoi(currentSver)
	//if sVer < config.C.SVer {
	//	return errno.SverOld
	//}
	return nil
}

// 校验P4Pclient版本号
func CheckP4PVersion(currentSver string) error {

	//if config.C.RunMode == "debug" {
	//	return nil
	//}
	//if currentSver == "" {
	//	return errno.SverOld
	//}
	//sVer, _ := strconv.Atoi(currentSver)
	//if sVer < config.C.P4pclientSver {
	//	return errno.SverOld
	//}
	return nil
}

// MD5 加密
func Md5Str(text string) string {
	c := md5.New()
	c.Write([]byte(text))
	return hex.EncodeToString(c.Sum(nil))
}

// sha1 加密
func Sha1Str(text string) string {
	h := sha1.New()
	io.WriteString(h, text)
	return hex.EncodeToString(h.Sum(nil))
}

// 校验签名 app 端
func CheckSign(sign string, args ...string) error {

	if config.C.RunMode == "debug" {
		return nil
	}

	var signString, md5Str string
	for _, v := range args {
		signString += v
	}
	md5Str = Md5Str(signString)
	if md5Str == sign || strings.ToUpper(md5Str) == sign {
		return nil
	}

	return errno.SignError
}

// trim 掉多余的空格和换行符
func Trim(str string) (newStr string) {

	// 将字符串的转换成[]rune
	strList := []rune(str)
	lth := len(strList)
	star := 0
	end := lth - 1
	for i := 0; i < lth; i++ {
		if star == i {
			if string(strList[i:i+1]) == " " {
				star++
			}
		} else {
			if string(strList[i:i+1]) == " " {
				end = i
			}
		}
	}

	if star < end {
		newStr = string(strList[star:end])
	}
	return
}

// 参数为空校验
func CheckEmptyParams(c *gin.Context, checkList []string) (err error, params map[string]string) {

	// 校验为空的 参数
	var emptyCheck []string

	params = make(map[string]string)
	for _, v := range checkList {
		if c.Query(v) == "" {
			emptyCheck = append(emptyCheck, v)
		} else {
			params[v] = c.Query(v)
		}
	}

	if len(emptyCheck) > 0 {
		errno.ParamsEmpty.Info = " 参数为空: {" + strings.Join(emptyCheck, ",") + "}"
		Log("Warn", errno.ParamsEmpty.Info)
		return errno.ParamsEmpty, params
	}

	return nil, params
}

// 获取当前时间的微秒数
func MicroTime() int64 {
	return time.Now().UnixNano() / 1000000
}

// 生成随机数
func RandInt(min, max int) int {

	if min == max {
		return min
	}
	rand.Seed(time.Now().Unix())
	return rand.Intn(max-min) + min
}

// 邮箱校验
func IsEmail(email string) bool {
	matched, _ := regexp.MatchString("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}$", email)
	return matched
}

//可使用6-20个字母、数字、下划线和减号,必须以字母开头(字母不区分大小写)
func IsWechat(wechat string) bool {
	matched, _ := regexp.MatchString("^[a-zA-Z][a-zA-Z0-9_-]{5,19}$", wechat)
	return matched
}

// 手机号校验
func IsPhone(phone string) bool {
	//return true
	matched, _ := regexp.MatchString("^\\d{1,18}$", phone)
	return matched
}

// Mac地址校验
func CheckMac(mac string) bool {
	matched, _ := regexp.MatchString("(([a-f0-9]{2}:)|([a-f0-9]{2}-)){5}[a-f0-9]{2}$", mac)
	return matched
}

// 校验密码是否正确
func CheckPassword(check, password, salt string) bool {
	if password == Md5Str(Md5Str(check)+salt) {
		return true
	}
	return false
}

// 校验密码是否正确
func CheckPasswordByWay(check, password, salt string, way int) bool {

	if way == 0 {
		if password == Md5Str(Md5Str(check)+salt) {
			return true
		}
	} else {
		Log("info", password)
		Log("info", Md5Str(check+salt))
		if password == Md5Str(check+salt) {
			return true
		}
	}

	return false
}

func CheckMd5Password(check, password, salt string) bool {
	if password == Md5Str(check+salt) {
		return true
	}
	return false
}

// 人人账号的密码规则：密码长度必须是6至20位,并且包含大小写字母及数字
func YYetsPasswordCheck(password string) bool {

	if len(password) > 20 || len(password) < 6 {
		fmt.Println("[Err] YYets Password Check: Error 0")
		return false
	}

	reg := regexp.MustCompile("[\\d]+?")
	if !reg.MatchString(password) {
		fmt.Println("[Err] YYets Password Check: Error 1")
		return false
	}

	reg = regexp.MustCompile("[a-z]+?")
	if !reg.MatchString(password) {
		fmt.Println("[Err] YYets Password Check:Error 2")
		return false
	}

	reg = regexp.MustCompile("[A-Z]+?")
	if !reg.MatchString(password) {
		fmt.Println("[Err] YYets Password Check:Error 3")
		return false
	}

	return true
}

// 盛天路由器管理密码校验
func STPasswordCheck(password string) bool {

	if len(password) > 20 || len(password) < 8 {
		fmt.Println("[Err] YYets Password Check: Error 4")
		return false
	}

	reg := regexp.MustCompile("[\\w]+?")
	if !reg.MatchString(password) {
		fmt.Println("[Err] YYets Password Check: Error 5")
		return false
	}

	return true
}

// 生成密码
func CreatePassword(password, salt string) string {
	return Md5Str(Md5Str(password) + salt)
}

func GetRandomNum(lenght int) string {
	str := "0123456789"
	bytes := []byte(str)
	var result []byte
	result = []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < lenght; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

func SubString(str string, begin, length int) (substr string) {
	// 将字符串的转换成[]rune
	rs := []rune(str)
	lth := len(rs)

	// 简单的越界判断
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}

	// 返回子串
	return string(rs[begin:end])
}

// 生成随机字符串
func GetRandomStr(lenght int) string {
	str := "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789"
	bytes := []byte(str)
	var result []byte
	result = []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < lenght; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

// IP地址转化为整型
func IpToInt(ip string) int64 {

	ret := big.NewInt(0)
	matched, _ := regexp.MatchString("(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)", ip)
	if matched == false {
		return ret.Int64()
	}

	ret.SetBytes(net.ParseIP(ip).To4())
	if ret.Int64() > 2147483647 {
		return 2147483647
	}
	return ret.Int64()
}

// 整型IP地址转化为192.168.1.1格式
func IpToString(ip int64) string {
	return fmt.Sprintf("%d.%d.%d.%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))
}

// 发送短信 【人人影视】 【YYeTs】
func SendSMS(phone string, area int, scene string) (int, error) {

	//if config.C.RunMode == "debug" {
	//	return 1111, nil
	//}

	areaPhone := "+" + strconv.Itoa(area) + phone
	// 生成随机 短信码
	codeNum := RandInt(1000, 9999)

	code := strconv.Itoa(codeNum)

	var smsCode string
	if scene == "transfer" && (area == 86 || area == 852 || area == 886 || area == 853) {
		smsCode = "【人人CVNT】您的确认码是" + code
	} else {
		if area == 86 || area == 852 || area == 886 || area == 853 {
			smsCode = "【人人CVNT】您的验证码是" + code
		} else if area == 82 {
			smsCode = "【YYeTs CVNT】당신의 인증코드는 " + code + " 입니다"
		} else if area == 81 {
			smsCode = "【YYeTs CVNT】あなたの認証番号は " + code
		} else {
			smsCode = "【YYeTs CVNT】Your verification code is " + code
		}
	}

	client := yp.New(config.C.YpApiKey)
	param := yp.NewParam(2)
	param[yp.MOBILE] = areaPhone
	param[yp.TEXT] = smsCode
	r := client.Sms().SingleSend(param)

	if r.Code == 0 {
		return codeNum, nil
	} else {
		return 0, errors.New(r.Msg)
	}
}

// 发送报警短信
func SendCronSMS(Phone, Task, Content string) (err error) {
	client := yp.New(config.C.YpApiKey)
	param := yp.NewParam(3)
	param[yp.MOBILE] = Phone
	param[yp.TPL_ID] = "3770584"
	param[yp.TPL_VALUE] = "#task#=" + Task + "&#result#=" + Content
	sms := client.Sms()
	sms.SetVersion("v1")
	r := sms.TplSend(param)
	if r.Code == 0 {
		return nil
	}
	return errno.SmsError
}

// 发送报警短信
func SendCronEnoughSMS(Phone, Name, CVN string) (err error) {
	client := yp.New(config.C.YpApiKey)
	param := yp.NewParam(3)
	param[yp.MOBILE] = Phone
	param[yp.TPL_ID] = "3197192"
	param[yp.TPL_VALUE] = "#name#=" + Name + "&#cvn#=" + CVN
	sms := client.Sms()
	sms.SetVersion("v1")
	r := sms.TplSend(param)
	if r.Code == 0 {
		return nil
	}
	return errno.SmsError
}

// 【人人CVNT】提示：当前总质押节点：#total#，今日结算节点：#pay#，代入公式f为：#f#。预计低保为：#cvn#。
func SendCronFSMS(Phone, Total, Pay, F, Cvn string) (err error) {
	client := yp.New(config.C.YpApiKey)
	param := yp.NewParam(3)
	param[yp.MOBILE] = Phone
	param[yp.TPL_ID] = "3210352"
	param[yp.TPL_VALUE] = "#total#=" + Total + "&#pay#=" + Pay + "&#f#=" + F + "&#cvn#=" + Cvn
	sms := client.Sms()
	sms.SetVersion("v1")
	r := sms.TplSend(param)
	if r.Code == 0 {
		return nil
	}
	return errno.SmsError
}

func EmailFindPassWord(email, code string) error {
	emailHtml := "\r\n" +
		"<p>尊敬的用户：</p> \r\n" + "<p></p>" +
		"<p align='left'>&nbsp;&nbsp;&nbsp;您好，收到这个邮件是因为有人使用您的邮箱进行密码找回。如果不是您本人操作，请忽略。<br/> 输入该验证码修改帐号密码：<strong>" + code + "</strong></p>" +
		"<p align='left'> </p>" +
		"<p align='left'>字幕组非常感谢您的使用。</p>"

	err := SendExMail(email, emailHtml, "字幕组,邮箱密码找回")
	return err
}

func SendExMail(to, email, subject string) error {
	m := gomail.NewMessage()
	m.SetHeader("From", config.C.Email.User)
	m.SetHeader("To", to)
	m.SetHeader("Subject", subject)
	m.SetBody("text/html", email)
	d := gomail.NewDialer(config.C.Email.Host, config.C.Email.Port, config.C.Email.User, config.C.Email.Password)
	if err := d.DialAndSend(m); err != nil {
		panic(err)
		return err
	}

	return nil
}

func PointFormat(point int64) (str string) {

	i := 0
	Units := map[int]string{0: "", 1: "万", 2: "亿", 3: "兆"}

Loop:
	for {
		if math.Abs(float64(point)) >= 10000 {
			point = point / 10000
			i++
			if i == 3 {
				break Loop
			}
		} else {
			break Loop
		}
	}

	newSize := ParseString(float64(point), 0)
	str = string(newSize) + Units[i]

	return
}

// 字节数转GB TB单位
func SizeFormat(byteSize interface{}, pre int) (str string) {
	byteSizeStr := fmt.Sprint(byteSize)
	byteSizeFloat64, err := strconv.ParseFloat(byteSizeStr, 64)
	if err != nil {
		Log("err", "字节转换失败")
	}

	i := 0
	Units := map[int]string{0: "B", 1: "KB", 2: "MB", 3: "GB", 4: "TB", 5: "PB", 6: "EB"}
Loop:
	for {
		if math.Abs(byteSizeFloat64) >= 1024 {
			byteSizeFloat64 = byteSizeFloat64 / 1024
			i++
			if i == 6 {
				break Loop
			}
		} else {
			break Loop
		}
	}

	newSize := ParseString(byteSizeFloat64, pre)
	str = string(newSize) + Units[i]

	return
}

// 字节数转GB TB单位
func SizeFormatMinKb(byteSize interface{}, pre int) (str string) {
	byteSizeStr := fmt.Sprint(byteSize)
	byteSizeFloat64, err := strconv.ParseFloat(byteSizeStr, 64)
	if err != nil {
		Log("err", "字节转换失败")
	}

	i := 0
	Units := map[int]string{0: "KB", 1: "MB", 2: "GB", 3: "TB", 4: "PB", 5: "EB"}
Loop:
	for {
		if math.Abs(byteSizeFloat64) >= 1024 {
			byteSizeFloat64 = byteSizeFloat64 / 1024
			i++
			if i == 5 {
				break Loop
			}
		} else {
			break Loop
		}
	}

	newSize := ParseString(byteSizeFloat64, pre)
	str = string(newSize) + Units[i]

	return
}

// 速度转化
func SpaceFormat(byteSize float64) (str string) {

	i := 0
	Units := map[int]string{0: "B/s", 1: "KB/s", 2: "MB/s", 3: "G/s", 4: "T/s"}

Loop:
	for {
		if math.Abs(byteSize) >= 1024 {
			byteSize = byteSize / 1024
			i++
			if i == 4 {
				break Loop
			}
		} else {
			break Loop
		}
	}
	newSize := fmt.Sprintf("%.1f", byteSize)
	str = string(newSize) + Units[i]

	return
}

// 相对路径转绝对图片路径  2018/1224/b_273cde81d79dc4851bade79ca0cb0061.jpg
func GetPicPath(url string) string {

	matched, _ := regexp.MatchString("^((https|http|ftp|rtsp|mms)?:\\/\\/)[^\\s]+", url)
	if !matched {
		return PicPathPrefix + url
	}
	return url
}

//获取今天凌晨的时间戳
func GetTodayZeroUnix() int64 {
	t := time.Now()
	zeroUnix := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()).Unix()

	return zeroUnix
}

//获取当前时间到明天凌晨的秒数差
func GetNowToNextDayUnix() (int64, error) {

	//获取明天凌晨的时间字符串
	nextDayStr := time.Now().Format("2006-01-02") + " 23:59:59"
	//时间字符串格式化
	nextDayTime, err := time.Parse("2006-01-02 15:04:05", nextDayStr)
	if err != nil {
		return 0, err
	}
	nextDayUnix := nextDayTime.Unix()
	//秒数差
	unixDiff := nextDayUnix - time.Now().Unix()

	return unixDiff, nil
}

// 时间格式转为时间戳
func StrToTime(t string) (unixTime int64) {
	timeTemp, err := time.Parse(TimeFormatS, t)
	if err == nil {
		unixTime = timeTemp.Unix() - TimeFormatCST
	}
	return
}

// 时间格式转为周
func StrTimeToWeek(t string) (result string) {
	var timeStr string
	timeStr = t + " 00:00:00"
	week := time.Unix(StrToTime(timeStr), 0).Weekday().String()
	switch week {
	case "Sunday":
		result = t + " 周日"
	case "Monday":
		result = t + " 周一"
	case "Tuesday":
		result = t + " 周二"
	case "Wednesday":
		result = t + " 周三"
	case "Thursday":
		result = t + " 周四"
	case "Friday":
		result = t + " 周五"
	case "Saturday":
		result = t + " 周六"
	default:
		result = t
	}

	return
}

// 时间戳转为时间字符串
func TimeToStr(t int64) (strTime string) {
	strTime = time.Unix(t, 0).Format(TimeFormatS)
	return
}

// 时间戳 输出为当前时间前 eg: 2分钟之前
func TimeFormatShow(t int64, tail string) (strTime string) {
	nowTime := time.Now().Unix()
	diff := t - nowTime
	if diff <= 0 {
		return ""
	}

	diffF := Int64ToFloat64(diff)
	if diff < TimeFormatHour { // 分钟 < 60 * 60
		strTime = strconv.FormatFloat(math.Ceil(diffF/TimeFormatMin), 'f', 0, 64) + "分钟" + tail
	} else if diff < TimeFormatDay { // 小时 < 60 * 60 * 24
		strTime = strconv.FormatFloat(math.Ceil(diffF/TimeFormatHour), 'f', 0, 64) + "小时" + tail
	} else if diff < TimeFormatWeek { // 天   < 60 * 60 * 24 * 7
		strTime = strconv.FormatFloat(math.Ceil(diffF/TimeFormatDay), 'f', 0, 64) + "天" + tail
	} else if diff < TimeFormatMonth { // 周   < 60 * 60 * 24 * 30
		strTime = strconv.FormatFloat(math.Ceil(diffF/TimeFormatWeek), 'f', 0, 64) + "周" + tail
	} else if diff < TimeFormatYear { // 月   < 60 * 60 * 24 * 365
		strTime = strconv.FormatFloat(math.Ceil(diffF/TimeFormatMonth), 'f', 0, 64) + "月" + tail
	} else if diff < TimeFormatTenYear { // 年   < 60 * 60 * 24 * 365 * 10
		strTime = strconv.FormatFloat(math.Ceil(diffF/TimeFormatYear), 'f', 0, 64) + "年" + tail
	} else { // 盘古开荒前
		strTime = "盘古开荒" + tail
	}

	return
}

// float64 转字符串保留两个小数
func ParseString(float642 float64, pre int) string {
	formatStr := "%.2f"
	if pre <= 0 {
		return strconv.Itoa(int(math.Floor(float642 + 0/5)))
	} else {
		formatStr = "%." + strconv.Itoa(pre) + "f"
	}
	return fmt.Sprintf(formatStr, float642)
}

func TransPinYin(str string) string {
	var trans string
	dict := pinyin.NewDict()
	trans = dict.Convert(str, "").None()
	return trans
}

//Int64  转 float64
func Int64ToFloat64(int64Data int64) float64 {
	dataStr := strconv.FormatInt(int64Data, 10)
	dataFloat, _ := strconv.ParseFloat(dataStr, 64)
	return dataFloat
}

func ReplaceString(str string) string {

	src := strings.Replace(str, "\\n", " ", -1)
	return src
}

//结构体转map
func Struct2Map(obj interface{}) map[string]interface{} {
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)

	var data = make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		data[t.Field(i).Tag.Get("json")] = v.Field(i).Interface()

	}
	return data
}

//map转struct,   map需跟struct的字段保持一致
//Auth: Xu
func Map2Struct(obj interface{}, objj interface{}, mapdata map[string]interface{}) {
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)
	//var data = mapdata
	for i := 0; i < t.NumField(); i++ {
		switch v.Field(i).Kind() {
		case reflect.Int:
			if _, ok := mapdata[t.Field(i).Tag.Get("json")]; ok {
				mapdata[t.Field(i).Tag.Get("json")], _ = strconv.Atoi(mapdata[t.Field(i).Tag.Get("json")].(string))
			}
		case reflect.Int64:
			if _, ok := mapdata[t.Field(i).Tag.Get("json")]; ok {
				mapdata[t.Field(i).Tag.Get("json")], _ = strconv.ParseInt(mapdata[t.Field(i).Tag.Get("json")].(string), 10, 64)
			}
		}
	}
	mapstructure.Decode(mapdata, objj)
}

//校验ETH钱包地址合法性
func CheckWalletERC20(address string) bool {
	address = strings.ToLower(address)
	ok, _ := regexp.MatchString("^(0x)[0-9a-fA-F]{40}$", address)
	return ok
}

func CheckWalletFormat(address, coinType string) (ok bool) {
	switch coinType {
	case COIN_TYPE_ERC20:
		ok = CheckWalletERC20(address)
	default:
		ok = false
	}
	return
}

//int64 转 int
func Int64ToInt(int64par int64) int {
	strInt64 := strconv.FormatInt(int64par, 10)
	intpar, _ := strconv.Atoi(strInt64)
	return intpar
}

//get请求
func HttpGet(url string, response interface{}) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	json.Unmarshal(body, response)
	return nil

}

//截取字符串
func Substr(str string, start int, end int) string {
	rs := []rune(str)
	return string(rs[start:end])
}

//加密支付密码
func EncryptPayPassword(password, salt string) string {
	password = strings.ToLower(password)
	str := password + PayPasswordKey + salt
	h := sha1.New()
	io.WriteString(h, str)
	encryptPassword := hex.EncodeToString(h.Sum(nil))
	return encryptPassword
}

//生成提现签名
func CreateWithdrawnSign(post []byte) string {
	str := string(post) + YqbWithdrawnKey
	sign := Sha1Str(str)
	return sign
}

//发送post请求
func HttpPostForm(url string, data url.Values) (body []byte, err error) {
	//打印日志
	jsonByte, err := json.Marshal(data)
	Log("info", url, " ", string(jsonByte))
	start := time.Now()
	resp, err := http.PostForm(url, data)
	if err != nil {
		Log("info", "调用远程接口失败：", err)
		return body, nil
	}
	defer resp.Body.Close()
	body, err = ioutil.ReadAll(resp.Body)
	//打印日志
	duration := time.Since(start)
	Log("Info", "调用远程接口耗时：", duration)
	if err != nil {
		Log("info", "读取返回数据失败：", err)
		return body, nil
	}
	return body, nil
}

//处理浮点数精度
func Decimal(value float64, n int) float64 {
	f := "%." + strconv.Itoa(n) + "f"
	value, _ = strconv.ParseFloat(fmt.Sprintf(f, value), 64)
	return value
}

//精度
func FormatValue(value interface{}, prec int) string {
	valueStr := fmt.Sprint(value)
	valueFloat64, _ := strconv.ParseFloat(valueStr, 64)
	re := strconv.FormatFloat(valueFloat64, 'f', prec, 64)
	return re
}

//经销商价格去掉小数点
func FormatPrice(value float64) int {
	str := strconv.FormatFloat(math.Floor(value), 'f', 0, 64)
	strInt, _ := strconv.Atoi(str)
	return strInt
}

//cvnt转换成万
func CvntFormat(cvnt interface{}) (str string) {
	cvntStr := fmt.Sprint(cvnt)
	cvntFloat64, _ := strconv.ParseFloat(cvntStr, 64)

	i := 0
	Units := map[int]string{0: "", 1: "万", 2: "亿"}

Loop:
	for {
		if math.Abs(float64(cvntFloat64)) >= 10000 {
			cvntFloat64 = cvntFloat64 / 10000
			i++
			if i == 2 {
				break Loop
			}
		} else {
			break Loop
		}
	}

	newSize := ParseString(float64(cvntFloat64), 2)
	str = string(newSize) + Units[i]

	return
}

//隐藏部分用户名
func NicknameFormat(name string) string {
	if len(name) == 11 {
		name = Substr(name, 0, 3) + "****" + Substr(name, 7, 11)
	} else if len(name) >= 2 {
		name = Substr(name, 0, 2) + "****"
	} else {
		name = name + "****"
	}
	return name
}

func ParseStringWithThousand(float642 float64, pre int) string {
	formatStr := "%.8f"
	if pre <= 0 {
		return strconv.Itoa(int(math.Floor(float642 + 0/5)))
	} else {
		formatStr = "%." + strconv.Itoa(pre) + "f"
	}
	p := message.NewPrinter(language.English)
	return p.Sprintf(formatStr, float642)
}

//解析POST数据
func ParsePostForm(bodyStr string) (params map[string]string) {
	params = make(map[string]string)
	data := strings.Split(bodyStr, "&")
	for _, value := range data {
		kv := strings.Split(value, "=")
		params[kv[0]] = kv[1]
	}
	return params
}

//map排序拼接为url参数
func SortParams(params map[string]string) string {
	keys := make([]string, len(params))
	i := 0
	for k, _ := range params {
		keys[i] = k
		i++
	}
	sort.Strings(keys)
	sorted := make([]string, len(params))
	i = 0
	for _, k := range keys {
		sorted[i] = k + "=" + url.QueryEscape(params[k])
		i++
	}
	return strings.Join(sorted, "&")
}

// 随机字符串
func Krand(size int, kind int, seed int64) string {
	ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
	is_all := kind > 2 || kind < 0
	rand.Seed(seed)
	for i := 0; i < size; i++ {
		if is_all {
			ikind = rand.Intn(3)
		}
		scope, base := kinds[ikind][0], kinds[ikind][1]
		result[i] = uint8(base + rand.Intn(scope))
	}
	str := string(result)
	return str
}

func Max(a, b int) int {
	if a >= b {
		return a
	} else {
		return b
	}
}

func Min(a, b int) int {
	if a <= b {
		return a
	} else {
		return b
	}
}

//发送HTTP请求
func HttpRequest(method string, api string, params map[string]string, headers map[string]string) (body []byte, err error) {
	var req *http.Request
	paramStr := SortParams(params)
	client := &http.Client{}
	if strings.ToUpper(method) == "GET" {
		if paramStr != "" {
			if strings.Index(api, "?") == -1 {
				api = api + "?" + paramStr
			} else {
				api = api + "&" + paramStr
			}
		}
		req, err = http.NewRequest("GET", api, nil)
	} else if strings.ToUpper(method) == "POST" {
		req, err = http.NewRequest("POST", api, strings.NewReader(paramStr))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	} else {
		err = errors.New("method not support")
		return body, err
	}
	if err != nil {
		return body, err
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	resp, err := client.Do(req)
	if err != nil {
		return body, err
	}
	defer resp.Body.Close()
	body, err = ioutil.ReadAll(resp.Body)
	return body, err
}

//判断浮点数相等
func FloatEqual(f1, f2 float64, n int) bool {
	if math.Abs(f1-f2) >= 1/math.Pow(10, float64(n)) {
		return false
	}
	return true
}

//计算下次请求时间
func NextRequestTime(n int64) int64 {
	t := math.Pow(2, float64(n)) * 5 * 60
	s := time.Now().Unix() + int64(t)
	return s
}

//判断切片中是否包含某个元素
func ContainInt(a []int, s int) bool {
	for _, v := range a {
		if v == s {
			return true
		}
	}
	return false
}

//计算总页数
func ListPage(countItem, pageSize int) (countPage int) {
	countPage = countItem / pageSize
	if countItem%pageSize > 0 {
		countPage++
	}
	return countPage
}

func CreateGateWaySign(t, params string) string {
	sign := Sha1Str(t + Md5Str(params) + config.C.Keys.GatewayKey)
	return sign
}
